
var eventListeners;
var perfCalculator;
var alertAdvicer;

var trialController;
var messageManager;
var perfHolder;

var alertSound = new Audio("sounds/mntAlert.mp3");

//var perfCalcualtor = new LastSessionPerformanceCalculator();

function setTrialController(tController) {
    trialController = tController;
}



//************
// Main method
//************

function controllerLoop(time) {
    processMechanicalCondition(time);
    processFeulInventory(time);

    messageManager.sendMessagesRoutine(time);
    trialController.processTutorial(time);
}

//Mechanical Condition parameters
var currentMC = 0;
var lastMalfunctionTime;

var currentSpeed = 0;
//var maintenanceTime = 0;
var severeSpeedChangeTime;
var severeSpeed;


function processMechanicalCondition(time) { // todo: implement sub method
    forceRepairIfNeeded(time,currentMC);
    newMc = calcNewMechanicalCondition(time);
    if (newMc > currentMC) {
        var sampler = getNewScenario().mechanicalEventSampler;
        var sample = sampler.sampling(time);
        // 1. write appropriate message.
        var content = {"from" : currentMC,"to" : newMc, "sample" : sample};
        addMessage(messages.mechanicalConditionChanged, content);

        // 2. update event listener
        eventListeners.onAction(currentTime, enumAction.MALFUNCTION_OCCUR, newMc);

        // 3. update new mechanical condition, speed and shoot rate.
        lastMalfunctionTime = time;
        currentMC = newMc;
        setShootingBreakPercent(getNewScenario().getShootingBreakPercent(currentMC));
        setSpaceshipSpeed(getNewScenario().getSpeed(currentMC));

        if (currentMC == enumMC.SEVERE) {
            severeSpeedChangeTime = time;
        }

        changeMechanicalCondition(currentMC);

        mechanicalActionDone();
    }
    calcSpeedAndShooutRate(time);
    processAlert(time);
}

function forceRepairIfNeeded(time, mc){
    if (mc != enumMC.FIX){
        var scenario = getNewScenario();
        var leftTime = scenario.gameLength - time;
        if (leftTime < scenario.getCostTable().getRepairTime(mc)){
            mechanicalActionDone();
        }
    }
}

function calcNewMechanicalCondition(time) {
    if (getNewScenario().mechanicalEventSampler.getNextTime() <= time) {
        if (currentMC < enumMC.SEVERE){
            return currentMC + 1;
        }
    }
    return currentMC;
}

function setSpaceshipSpeed(speed1) {
    if (speed1 > 0){
        currentSpeed = speed1;
    } else {
        if (currentSpeed > 0){
            currentSpeed = 0;
            panelController.onFreezeDueToSeverMalfunction();
        }
    }
    game.ship.setSpeed(currentSpeed);
}

function calcSpeedAndShooutRate(time) {
    if (currentMC == enumMC.SEVERE) {
        if (time > severeSpeedChangeTime) {
            setSpaceshipSpeed(currentSpeed - 1);
            setShootingBreakPercent(game.ship.fireRate * 1.5);
            severeSpeedChangeTime = time + 2*1000;
        }
    }
}

function getCurrentMechanicalCondition() {
    return currentMC;
}

var alertBeforeDisplayed = false;
var nextSnoozeDisplayed = false;
var timeOfNextSnooze = 0;

function processAlert(time) {
    netScore = perfCalculator.getNetPerformance(time).netScore;
    netTime = perfCalculator.getNetTime(time);
    if (alertAdvicer.isTimeToDisplayAlert(netScore, netTime, time) == true) {
        game.flashBackground.flash(time);
        alertSound.loop = true;
        alertSound.play();
        var content = {
            netScore: netScore,
            displayTime: alertAdvicer.getRecomendedAlertTime(netScore),
            recomendedTime: alertAdvicer.getFixRecommendedTime(netScore), // fix recommended time
            duration: getNewScenario().gameLength,
        }
        console.log("perData\t" + time, JSON.stringify(content));
        console.log("perfCalculator\t", JSON.stringify(perfCalculator.buckets));
        addMessage(messages.alertBeforeDisplayed, content);
        panelController.onMaintenanceAlert(getNewScenario().gameLength);    
    } 
}

//called when player click on mechanical action button.
function mechanicalActionDone() {
    alertSound.pause();
    alertSound.load();

    repairCost = getNewScenario().getCostTable().getRepairCost(currentMC);
    game.maintenanceOrRepairScore.init(game.ship.x, game.ship.y, repairCost, false, currentTime);
    game.flashBackground.stop();

    eventListeners.onAction(currentTime, enumAction.REPAIR);

    trialController.onActionDone(enumAction.REPAIR);
    panelController.onMalfunctionRepair(currentMC);

    addPerformanceReportMessage();
    var content = {
        malfunctionTime : lastMalfunctionTime
    };
    addMessage(messages.repairAction, content);

    if (currentMC != enumMC.FIX) {
        var actionTime = getNewScenario().getCostTable().getRepairTime(currentMC);
        var actionCost = getNewScenario().getCostTable().getRepairCost(currentMC);
		
        currentMC = enumMC.FIX;
        changeMechanicalCondition(enumMC.FIX);
        setShootingBreakPercent(getNewScenario().getShootingBreakPercent(currentMC));
        setSpaceshipSpeed(getNewScenario().getSpeed(currentMC));

        increaseScore(-actionCost);
        freezeSpaceship(actionTime);
    }
}

function maintenanceActionDone() {
    alertSound.pause();
    alertSound.load();

    game.flashBackground.stop();
    
    

    eventListeners.onAction(currentTime, enumAction.MAINTENANCE);
    if (trialController.onActionDone(enumAction.MAINTENANCE) == false) {
        return;
    }
    maintenanceCost = getNewScenario().getCostTable().getCost(enumAction.MAINTENANCE);
    maintenanceDuration = getNewScenario().getCostTable().getTime(enumAction.MAINTENANCE);

    game.maintenanceOrRepairScore.init(game.ship.x, game.ship.y, maintenanceCost, false, currentTime);

    var sampleValue = getNewScenario().mechanicalEventSampler.sampling(currentTime);

    addPerformanceReportMessage();
    var content = {
        sampleValue : sampleValue
    };
    addMessage(messages.maintenaneAction, content);

    increaseScore(-maintenanceCost);

    panelController.onMaintenanceDone(maintenanceDuration);
    freezeSpaceship(maintenanceDuration);
}


//*************************************
//Fuel
//*************************************

var lastTimeFeulStationTime = 0;
var stationsLocation = [];

function processFeulInventory(time) {

    if (game.feulStatus <= 0) {
        //seen that total time of fill feul by spaceship is: (delay before time + flight time + fill time)
        callToFeulSpaceship(getNewScenario().costTable.getTime(enumAction.WAIT_TO_FUEL_SHIP));
    }
    calcNextStation(time);
    // warning strategy will be implemented later
}

function calcNextStation(time) {
    if (getNewScenario().fuelStationSampler.getNextTime() <= time){

        // save time of fuel station creation.
        if (stationsLocation == undefined) {
            stationsLocation = [];
        }
        stationsLocation.push(time);

        // create new fuel station.
        var x = Math.floor(Math.random() * (Background.prototype.canvasWidth - 2 * imageRepository.feulship.width - 20) / imageRepository.feulship.width) * imageRepository.feulship.width + imageRepository.feulship.width + 10;
        makeAnewFeulStation(x);

        addMessage(messages.feulStationCreated, {});

        // determine the next time of fuel station creation.
        getNewScenario().fuelStationSampler.sampling(time);
    }
}

//Called when spaceship stop in fuel station.
function feulFillDone() {
    
    trialController.onActionDone(enumAction.REFULING);
    addPerformanceReportMessage();
    addMessage(messages.feulFillDone, {});

    var scenario = getNewScenario();
    var costTable = scenario.getCostTable();
    var maxFuel = scenario.getMaxFeulInventory();
	
    var fuelCost = costTable.getRefuelingCost(maxFuel, game.feulStatus);
    eventListeners.onRefuel(currentTime, fuelCost);
    increaseScore(-fuelCost);
    setFeulInventory(getNewScenario().getMaxFeulInventory());
    //increaseScore(-getNewScenario().costTable.getCost(enumAction.REFULING));
	

    var sec = getNewScenario().costTable.getTime(enumAction.REFULING);
    console.log("feulFillDone", sec);
    freezeSpaceship(sec);
    panelController.onRefueling(sec);
    return fuelCost;
}

function feulFillBySpaceship() {
    trialController.onActionDone(enumAction.REFULING_BY_FUEL_SHIP);
    addPerformanceReportMessage();
    addMessage(messages.feulFillBySpaceShipDone, {});

    setFeulInventory(getNewScenario().getMaxFeulInventory());
    increaseScore(-getNewScenario().costTable.getCost(enumAction.REFULING_BY_FUEL_SHIP));

    var sec = getNewScenario().costTable.getTime(enumAction.REFULING_BY_FUEL_SHIP);
    freezeSpaceship(sec);
    panelController.onRefueling(sec);
}

function onSpaceshipFreeze(currentTime, freezeDuration) {
    eventListeners.onSpaceshipFreeze(currentTime, freezeDuration);
}

//*************
//Performance  
//*************

function onMeteorShootDown() {
    eventListeners.onAction(currentTime, enumAction.SHUTDOWN);
    perfHolder.onMeteorShootDown(currentTime);
}

function onMeteorCollision() {
    eventListeners.onAction(currentTime, enumAction.COLISSION);
    perfHolder.onMeteorCollision(currentTime);
}

function onFirePressed() {
    perfHolder.onFirePressed(currentTime);
}



//**********************
// initial & finish game
//**********************

function initParms() {
    var scenario = getNewScenario();

    eventListeners = new GameEventListenerList();
    //eventListeners.addListener(new DebugGameEventListener());

    //perfCalculator = new LastSessionPerformanceCalculator();
    //perfCalculator = new LastTimeSegmentPerformanceCalculator(20000, scenario.meteorScore, scenario.hitByMeteorScore);
    perfCalculator = new DiscountFactorPerformanceCalculator(10.5, 0.941, scenario.meteorScore, scenario.hitByMeteorScore);
    eventListeners.addListener(perfCalculator);

    alertAdvicer;
    switch (curStrategy) {
        case NPA:
        case previewStrategy:
        case heatingGame:
            alertAdvicer = new NonAdviser(); break;
        case GPA: alertAdvicer = new AdviserByFixTime(20000); break;
        case FPA: alertAdvicer = new AdviserByCurrentSession(); break;
    }
    //alertAdvicer = new AdviserByFixTime(8000);
    eventListeners.addListener(alertAdvicer);
    
   
    perfHolder = new PerformanceHolder();
    messageManager = new GameMessageBuffer(curStrategy.name, window.currentGame, window.assignmentId);

    if (game) {
        game.playerScore = 0;
    }
    //set parameters
    if (currentMC != enumMC.FIX) {
        changeMechanicalCondition(enumMC.FIX);
    }

    
    scenario.mechanicalEventSampler.sampling(0);
    scenario.fuelStationSampler.sampling(0);

    currentSpeed = scenario.getSpeed(enumMC.FIX);
    currentMC = enumMC.FIX;

    msgSeqNumber = 0;
    addMessage(messages.gameStart, {});
}

function onGameFinish() {
    sendRestMessages();
}

//****************************************************************************************************************************************
//****************************************************************************************************************************************
//All methods that embedded in control loop and their implementation should be different in controllerPreview.js should be located under this row.
//****************************************************************************************************************************************
//****************************************************************************************************************************************



//********
//Messages
//********

var msgSeqNumber;

function getHeader(msgTitle){
    msgSeqNumber++;

    var score = 0;
    var fuel = 0;
    var time = 0;
    if (game != undefined && game.playerScore != undefined) {
        score = game.playerScore;
    }

    if (game != undefined && game.feulStatus != undefined) {
        fuel = game.feulStatus;
    }
   
    if (currentTime != undefined) {
        time = currentTime;
    }
    var header = {
        "time": time,
        "seqNumber": msgSeqNumber,
        "score" : score,
        "mc" : currentMC,
        "fuel": fuel,
        "msgCode" : msgTitle.type,
        "msgTitle" : msgTitle.name
    };

    return header;
}

function addMessage(msgTitle, content){
    var msg = {
        "header" : getHeader(msgTitle),
        "content" : JSON.stringify(content)
    };

    messageManager.addMessage(msg);
}

function addPerformanceReportMessage(){
    content = perfHolder.getPerformanceDataOfLastSession();
    addMessage(messages.meteorSummery, content);
}

function sendRestMessages(){
    addPerformanceReportMessage();
    addMessage(messages.gameEnd, {});
    messageManager.sendRestMessages();
}

var showUserDialoge = true;
function writeMsgForUser(title, msg) {
    $("#chack").show();
    $("#diaog-text").html(msg);
    $("#dialog-message").dialog({
        modal: false,
        title: title,
        width: 400,
        position: { my: "center", at: "center", of: $("#main") },
        buttons: [{
            text: "Ok",
            click: function () {
                if ($("#showMsg").is(':checked')) {
                    showUserDialoge = false;
                }
                $(this).dialog("close");
                $("#chack").hide();
                pauseGame = false;
                timer.Timer.play();
                animate();


            }
        }]
    });
    pauseGame = true;
    timer.Timer.pause();
}




